今天要來聊聊flutter是怎麼長出一顆完整的樹的
我們先看程式碼
void main() {
runApp(
const Center(
child: Text(
'Hello, world!',
textDirection: TextDirection.ltr,
),
),
);
}
老樣子我們往source code去看,這次是從runApp開始!
void runApp(Widget app) {
WidgetsFlutterBinding.ensureInitialized()
..scheduleAttachRootWidget(app)
..scheduleWarmUpFrame();
}
@protected
void scheduleAttachRootWidget(Widget rootWidget) {
Timer.run(() {
attachRootWidget(rootWidget);
});
}
void attachRootWidget(Widget rootWidget) {
final bool isBootstrapFrame = renderViewElement == null;
_readyToProduceFrames = true;
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
container: renderView,
debugShortDescription: '[root]',
child: rootWidget,
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
if (isBootstrapFrame) {
SchedulerBinding.instance.ensureVisualUpdate();
}
}
RenderObjectToWidgetElement<T> attachToRenderTree(BuildOwner owner, [ RenderObjectToWidgetElement<T>? element ]) {
if (element == null) {
owner.lockState(() {
element = createElement();
assert(element != null);
element!.assignOwner(owner);
});
owner.buildScope(element!, () {
element!.mount(null, null);
});
} else {
element._newWidget = this;
element.markNeedsBuild();
}
return element!;
}
可以widget先丟進runApp以後,create WidgetsFlutterBinding並將widget一路丟進scheduleAttachRootWidget -> attachRootWidget ,然後create RenderObjectToWidgetAdapter<RenderBox>\它是一個Widget(嚴格來說是RenderObjectWidget)並把路帶進來的widget當做它的child,最後RenderObjectToWidgetAdapter呼叫attachToRenderTree,裡面的代碼會將widget inflat into element並設成root element。
OK,看到這裡可能會有點矇,但是這段流程其實就是把我們設計好的widgets放到RenderObjectToWidgetAdapter底下並且執行inflate將一個個的widget轉化成element
今天用簡單的代碼介紹了widget tree & element tree的root是怎麼產生的,明天會介紹到子結點是怎麼透過update串到這兩棵樹上